import { Socket } from 'net';
import { connect as tlsConnect, TLSSocket } from 'tls';
import { Response, ResponseType } from './Response';
type MessageHandler = {
  fn: (buffer: Buffer) => void;
  once?: boolean;
};

export class MailSocket {
  private socket: Socket | TLSSocket;
  private onMessageHandlerMap: Map<string, MessageHandler>;

  constructor() {
    // 初始化为普通 Socket，实际连接时再决定
    this.socket = new Socket();
    this.onMessageHandlerMap = new Map();
  }

  public getSocket() {
    return this.socket;
  }

  private dispatchMessageEvent(data: Buffer) {
    this.onMessageHandlerMap.forEach((handler, id) => {
      handler.fn(data);
      if (handler.once) {
        this.onMessageHandlerMap.delete(id);
      }
    });
  }

  private dispatchErrorEvent(err: Error) {}

  public close() {
    this.socket.destroy();
  }

  /**
   * 支持 TLS 连接
   * @param host 邮箱服务器
   * @param port 端口
   * @param useTLS 是否启用TLS
   */
  public async connect(host: string, port: number, useTLS = false) {
    return new Promise<ResponseType>((resolve) => {
      if (useTLS) {
        // TLS 连接
        const tlsSocket = tlsConnect(
          {
            host,
            port,
            servername: host, // SNI
            rejectUnauthorized: false // 如需验证证书可设为true
          },
          () => {
            this.socket = tlsSocket;
            this.socket.on('data', (data) => this.dispatchMessageEvent(data));
            this.socket.on('error', (err) => this.dispatchErrorEvent(err));
            resolve(Response(200, 'connect success', void 0));
          }
        );
        tlsSocket.setTimeout(10000, () => {
          resolve(Response(201, 'connect timeout', new Error('MailSocket:timeout')));
        });
      } else {
        // 普通TCP
        this.socket = new Socket();
        this.socket.connect({ host, port, family: 4 }, () => {
          this.socket.on('data', (data) => this.dispatchMessageEvent(data));
          this.socket.on('error', (err) => this.dispatchErrorEvent(err));
          resolve(Response(200, 'connect success', void 0));
        });
        setTimeout(() => {
          resolve(Response(201, 'connect timeout', new Error('MailSocket:timeout')));
        }, 10_000);
      }
    });
  }

  public setMessageListener(id: string, handler: MessageHandler) {
    this.onMessageHandlerMap.set(id, handler);
  }

  public removeMessageListener(target: string | Function | MessageHandler) {
    if (typeof target === 'string') {
      this.onMessageHandlerMap.delete(target);
    } else if (typeof target === 'function') {
      this.onMessageHandlerMap.forEach((handler, id) => {
        if (handler.fn === target) {
          this.onMessageHandlerMap.delete(id);
        }
      });
    } else {
      this.onMessageHandlerMap.forEach((handler, id) => {
        if (handler === target) {
          this.onMessageHandlerMap.delete(id);
        }
      });
    }
  }

  public send(data: string | Uint8Array) {
    return new Promise<ResponseType>((resolve) => {
      this.socket.write(data, (err) => {
        if (!err) {
          resolve(Response(200, 'send data success', void 0));
        } else {
          resolve(Response(202, 'send data error', err));
        }
      });
    });
  }
}
